package com.zwr.normal.readwrite;

import java.util.concurrent.locks.StampedLock;

import static java.lang.Thread.sleep;

/**
 * @author Administrator
 */
public class DataContainerStamped {
    private int data;
    private final StampedLock lock = new StampedLock();
    public DataContainerStamped(int data) {
        this.data = data;
    }
    public int read(int readTime) throws InterruptedException {
        long stamp = lock.tryOptimisticRead();
        System.out.println("optimistic read locking..." + stamp);
        sleep(readTime);
        if (lock.validate(stamp)) {
            System.out.println("read finish..."+ stamp  +" data: " + data);
            return data;
        }
        // 锁升级 - 读锁
        System.out.println("updating to read lock... " + stamp);
        try {
            stamp = lock.readLock();
            System.out.println("read lock "+ stamp);
            sleep(readTime);
            System.out.println("read finish..."+stamp +" data:" + data);
            return data;
        } finally {
            System.out.println("read unlock " + stamp);
            lock.unlockRead(stamp);
        }
    }
    public void write(int newData) {
        long stamp = lock.writeLock();
        System.out.println("write lock " + stamp);
        try {
            try {
                sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.data = newData;
        } finally {
            System.out.println("write unlock " +  stamp);
            lock.unlockWrite(stamp);
        }
    }

    public static void main(String[] args) {
        //测试 读-读 可以优化
        DataContainerStamped dataContainer = new DataContainerStamped(1);
        new Thread(() -> {
            try {
                dataContainer.read(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t1").start();

        try {
            sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            try {
                dataContainer.read(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t2").start();
    }
}
